import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Map.Entry;

import com.modestmaps.core.Point2f;
import com.modestmaps.geo.Location;

import processing.core.PImage;

public class MapArea extends GuiElement{

	int[] valuesPerHour = new int[24];
	int dia;

	PlotsPanel plotsPanel;
	map_updateFiltersResults_Thread thread = new map_updateFiltersResults_Thread();


	public MapArea(float x, float y, float w, float h) {
		this.x = x;
		this.y = y;
		width = w;
		height = h;

		plotsPanel = new PlotsPanel(0, 375, 500, 300);

	} 


	public void draw() {	

		// Plot dots on map
		GLOBAL.processing.strokeWeight(2);
		GLOBAL.processing.stroke(20,200);

		Nationality highlight_nat = null;
		float highlight_value=0, highlightX=0,highlightY=0,highlightDia=0;
		boolean highlight = false;
		
		try{
		for (Entry<Nationality,Integer> entry : GLOBAL.map_usersPerNationality.entrySet()) {
			Nationality nationality = entry.getKey();
			Integer users = entry.getValue();
			
			if (users.intValue() == 0 ) continue;
			
			if (GLOBAL.continents_colors)
				GLOBAL.processing.fill(nationality.continent.color, 230);
			else
				GLOBAL.processing.fill(nationality.color, 230);
			
			dia = 15 + users/2;
			//System.out.println(users);

			Point2f p = GLOBAL.mapClass.map.locationPoint(new Location(nationality.latitude, nationality.longitude));

			if (p.x >= x - 20 && p.x <= (GLOBAL.processing.width + 20)
					&& p.y >= y - 10 && p.y <= y + GLOBAL.processing.height) {
				GLOBAL.processing.ellipse(p.x, p.y, dia, dia);
				
				// Save selected sightings
				if (GLOBAL.processing.mouseX > p.x - dia/2
						&& GLOBAL.processing.mouseX < p.x + dia/2
						&& GLOBAL.processing.mouseY > p.y - dia/2
						&& GLOBAL.processing.mouseY < p.y + dia/2) {
					highlight = true;
					highlight_nat = nationality;
					highlight_value = users.intValue();
					highlightX = p.x;
					highlightY = p.y;
					highlightDia = dia;
				}

			}

		}
	}catch (Exception e){
		return;
	}
		if (highlight) {
			drawHighlight(highlight_nat, highlight_value, 
					highlightX, highlightY, highlightDia, highlightDia);
		}

		plotsPanel.draw();
	}
	
	
	public void drawHighlight(Nationality highlight_nat, float highlight_value, float highlightX, float highlightY, float highlightDia, float highlightDia2) {
		GLOBAL.processing.fill(80, 80, 80,100);
		GLOBAL.processing.ellipse(highlightX, highlightY, highlightDia, highlightDia);
		
		int x1 = GLOBAL.processing.mouseX + 15;
		int y1 = GLOBAL.processing.mouseY - 8 ;
		
		float width = GLOBAL.processing.textWidth(highlight_nat.getName());
		
		if (width < GLOBAL.processing.textWidth("# of users: "+(int)highlight_value))
			width = GLOBAL.processing.textWidth("# of users: "+(int)highlight_value);
		
		if ( x1 + width > GLOBAL.processing.width)
			x1 -= (width + 45);
		
		// Rectangle
		GLOBAL.processing.noStroke();
		GLOBAL.processing.rectMode(GLOBAL.processing.CORNER);
		GLOBAL.processing.fill(GLOBAL.colorBackground);
		GLOBAL.processing.rect( x1, y1 , width + 15, 40); //x,y,width,height
	
		// Text
		GLOBAL.processing.fill(GLOBAL.textColor);
		GLOBAL.processing.textFont(GLOBAL.plotFont,14);
		GLOBAL.processing.textAlign(GLOBAL.processing.LEFT);
		GLOBAL.processing.text(highlight_nat.getName() , x1+4, y1+15);
		GLOBAL.processing.text("# of users: "+(int)highlight_value, x1+4, y1+35); 
	}

	public void mousePressed() {
		if(plotsPanel.mouseOver() || plotsPanel.plotsControl.mouseOver())
			plotsPanel.mousePressed();
	}

	public void updateFiltersResults() {
		if(thread.isAlive())thread.stop();
		thread = new map_updateFiltersResults_Thread();
		thread.start();
	}

	// Side panel
	public class PlotsPanel extends AnimatedGuiElement {

		public GuiElement plotsControl;
		public boolean hide = false;
		PImage panelImg;

		LineChart chart;
		//BarChart chart;

		public PlotsPanel(float x, float y, float w, float h) {

			super(x,y);
			this.x = x;
			this.y = y;
			width = w;
			height = h;

			// Chart panel controller 
			plotsControl = new GuiElement();
			plotsControl.x = x + width;
			plotsControl.y = y-1;
			plotsControl.width = 20;
			plotsControl.height = 100;

			panelImg = GLOBAL.processing.loadImage("chart.png");

			//chart = new BarChart(x+40, y+15, w-60, h, 0);
			// Create Line Chart
			chart = new LineChart(x+40, y+15, w -60, h, 0, 23);
			
			
		}

		public void draw() {
			// Update the animation
			if ( GLOBAL.processing.abs(targetX-x) < 1
					&& GLOBAL.processing.abs(targetY-y) < 1  )
				targeting = false;
			else
				super.update();

			GLOBAL.processing.noStroke();
			GLOBAL.processing.rectMode(GLOBAL.processing.CORNERS);
			GLOBAL.processing.fill(GLOBAL.menuColor);
			GLOBAL.processing.rect(x, y, x+width, y+height);

			GLOBAL.processing.strokeWeight(2);
			GLOBAL.processing.stroke(80);
			GLOBAL.processing.line(x + width, y, x+ width, y+height);
			GLOBAL.processing.line(x, y, x+ width, y);
			GLOBAL.processing.line(x, y + height, x + width, y + height);
			GLOBAL.processing.noFill();

			// Menu icon
			plotsControl.x = x + width;
			plotsControl.y = y-1;
			if (panelImg != null)
				GLOBAL.processing.image(panelImg, x+width, plotsControl.y);

			if (this.x + this.width > 5) {
				chart.x = this.x + 40;
				chart.draw();
			}

		}

		public void mousePressed() {

			if (plotsControl.mouseOver()) {
				if(!hide) {
					super.target(x - width, y);
					hide = true;
				}
				else {
					super.target(x + width, y);
					hide = false;
				}
				return;
			}
		}

	}


	public class map_updateFiltersResults_Thread extends Thread{

		DateFormat df = new SimpleDateFormat("H");

		String ageString, completeSexString;

		public void run() {

			Statement stmt;
			ResultSet res ;

			Calendar datePosted = Calendar.getInstance();
			Date datePostedParsed;

			GLOBAL.map_nPerHourPerNationality.clear();
			GLOBAL.map_usersPerNationality.clear();
			
			GLOBAL.map_nPerHourPerContinent.clear();
			GLOBAL.map_usersPerContinent.clear();
			
			if (GLOBAL.nationalitiesSelected.size() == 0) return;
			
			// Sex Strings
			String maleString=null, femaleString=null, unknownString;
			
			if(GLOBAL.selectionPanel.m.state)
				maleString = "U.sex = 'm' OR ";
			if(GLOBAL.selectionPanel.f.state)
				femaleString = "U.sex = 'f' OR ";
			unknownString = "U.sex = ''";
			
			// Complete Sex String
			completeSexString="";
			
			if(maleString!=null)
				completeSexString = maleString;
			if(femaleString!=null)
				completeSexString = completeSexString.concat(femaleString);
			completeSexString = completeSexString.concat(unknownString);
			
			
			// Age String
			
			ageString = "( U.age >= '"+ GLOBAL.ageStart +"' AND U.age<= '"+ GLOBAL.ageEnd+"' ) ";
			
			if (GLOBAL.age_undefinedSelected)
				ageString += " OR U.age = '' ";


			// user count
			for (int k=0; k<GLOBAL.nationalitiesSelected.size(); k++) {
				Nationality nat = GLOBAL.nationalitiesSelected.get(k);
				Continent cont = nat.continent;
				try {				
					String sql = "SELECT count(*) as n from usersTime as U where " +
							"nationality == '"+nat.name+"' AND ("+
							ageString+" ) AND ("+
							completeSexString+ " );";
					//System.out.println(sql);
					stmt = GLOBAL.user_times_con.createStatement();
					res = stmt.executeQuery(sql);
				}
				catch(SQLException e){
					System.out.println("Error creating or running statement: " + e.toString());
					return;
				}
				
				try{	
					if(res.getInt("n")==0)
						GLOBAL.map_usersPerNationality.put(nat, new Integer(0));
					else
						GLOBAL.map_usersPerNationality.put(nat, new Integer(res.getInt("n")));
//					System.out.println(res.getInt("n"));
					Integer current_value = GLOBAL.map_usersPerContinent.get(cont);
					if (current_value == null) {
						// Continent empty
						GLOBAL.map_usersPerContinent.put(cont, GLOBAL.map_usersPerNationality.get(nat)); // save this nat value
					}
					else {
						// Continent exists
						GLOBAL.map_usersPerContinent.put(cont, current_value + GLOBAL.map_usersPerNationality.get(nat)); // increment with this nat value
					}
				}
				catch(Exception e){
					System.out.println("Error processing results: " + e.toString());
					try{
						GLOBAL.map_usersPerNationality.put(nat, new Integer(0));
						res.close();
						stmt.close();
					}
					catch(Exception ex) {}
					return;
				}
			}

			try
			{

				// Prepare nationalities selected
				String nat = GLOBAL.nationalitiesSelected.get(0).getName();
				if (GLOBAL.nationalitiesSelected.size() > 1)
					for (int i=1; i<GLOBAL.nationalitiesSelected.size(); i++) {
						nat = nat + "' OR U.nationality == '" + GLOBAL.nationalitiesSelected.get(i).name;
					}
				//
				//System.out.println(nat);
				String sql = "SELECT T.hour, T.plays, U.nationality from usersTime as U " +
						"INNER JOIN times as T on U.user_code = T.user_code where " +
						"( U.nationality = '"+nat+"' ) AND ("+
						ageString+" ) AND ("+
						completeSexString+") ;";
				//System.out.println(sql);
				stmt = GLOBAL.user_times_con.createStatement();
				res = stmt.executeQuery(sql);

			}
			catch(SQLException e)
			{
				System.out.println("Error creating or running statement: " + e.toString());
				return;
			}


			try
			{
				String date;
				float plays;
				String nationality;

				for (Entry<String,Nationality> entry : GLOBAL.hashMapNationalitiesSelected.entrySet()) {
					ArrayList<Float> value_per_hour = new ArrayList<Float>(24);
					for (int j=0; j<24 ; j++)
						value_per_hour.add(0f);
					GLOBAL.map_nPerHourPerNationality.put(entry.getValue(), value_per_hour);
					GLOBAL.map_nPerHourPerContinent.put(entry.getValue().continent, value_per_hour);
				}

				while(res.next())
				{
					// get hour and parse
					datePostedParsed = df.parse(res.getString("hour"));
					datePosted.setTime(datePostedParsed);
					datePosted.set(Calendar.MONTH, datePosted.get(Calendar.MONTH));

					// get plays and nationality and continent
					plays = res.getFloat("plays");
					nationality = res.getString("nationality");
					Nationality n = GLOBAL.hashMapNationalitiesSelected.get(nationality);
					Continent cont = n.continent;
					
					// update n. of plays in nationality
					Float value = GLOBAL.map_nPerHourPerNationality
							.get(n)
								.get(datePosted.get(Calendar.HOUR_OF_DAY));
					GLOBAL.map_nPerHourPerNationality
						.get(n)
							.set(datePosted.get(Calendar.HOUR_OF_DAY), value + plays);
					
					// update n. of plays per continent
					Float current_value = GLOBAL.map_nPerHourPerContinent.get(cont).get(datePosted.get(Calendar.HOUR_OF_DAY));
					GLOBAL.map_nPerHourPerContinent.get(cont).set(datePosted.get(Calendar.HOUR_OF_DAY), current_value + plays);
					
				}

			}
			catch(Exception e){
				System.out.println("Error processing results: " + e.toString());
				//e.printStackTrace();
				try{
					res.close();
					stmt.close();
				}
				catch(Exception ex) {}
				return;
			}

		}
	}

}
